﻿using System;
using System.IO;
using System.Net;
using System.Threading;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.Ex.DataStruct;
using UtilZ.Dotnet.Ex.Model;
using UtilZ.Dotnet.Ex.SequenceDB;

namespace ConAppCore.Test
{
    internal class TestSequenceDB : ISequenceDataFilter, IDisposable
    {
        public static void Test()
        {
            try
            {
                using var obj = new TestSequenceDB();
                obj.TestSequenceDB1();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }




        private readonly string _dir = @"D:\Temp";
        private readonly int _perFileCount = 5;
        private readonly SequenceDatabase _sdb;
        private readonly SingleTypeObjectPool<ISequenceData> _pool;

        private TestSequenceDB()
        {
            this._sdb = new SequenceDatabase(1, this._dir, ".dat", this._perFileCount);

            this._pool = new SingleTypeObjectPool<ISequenceData>();
            this._pool.TakeTimeoutResolve += Pool_ObjectResolve;
        }


        bool ISequenceDataFilter.Filter(ISequenceData data)
        {
            var tdata = (TestSequenceData)data;

            if (tdata.Time > DateTime.Parse("2025-09-10 20:12:36"))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        private readonly AutoResetEvent _eventHandler = new AutoResetEvent(false);
        private void TestSequenceDB1()
        {
            int interval = 3;
            DateTime refTime = DateTime.Parse("2025-9-10 12:12:30");

            if (Directory.GetFiles(this._dir).Length <= 0)
            {
                Console.WriteLine("WriteData");
                WriteData(refTime, interval);
            }

            Console.WriteLine("ReplayData");
            ReplayData(refTime, interval);
        }

        private void WriteData(DateTime refTime, int interval)
        {
            int value = 0;
            TestSequenceData item;

            for (int i = 0; i < this._perFileCount; i++)
            {
                //if (!this._pool.TryTake(out ISequenceData obj))
                //{
                //    item = (TestSequenceData)obj;
                //}

                item = (TestSequenceData)this._pool.Take(0);
                item.Update(refTime.AddSeconds(interval * value), value++);
                this._sdb.Add(item);
                Console.WriteLine($"Add Time:{item.Time.ToString("yyyy-MM-dd HH:mm:ss.fff")} Value:{item.Value}");
            }
        }

        private void ReplayData(DateTime refTime, int interval)
        {
            //var sdr = new SequenceDataReplay("11", this._pool, this._sdb, this, ReplayDataOuputCallback, ReplayEndCallback);
            using var sdr = new SequenceDataReplay("11", this._pool, this._sdb, null, ReplayDataOuputCallback, ReplayEndCallback);
            sdr.ReplaySpeed = 5;
            int count = sdr.SetIndexRange(TimeEx.GetTimestamp(refTime), TimeEx.GetTimestamp(refTime.AddSeconds(interval * _perFileCount)), new IPEndPoint(IPAddress.Parse("192.168.10.123"), 2568));
            Console.WriteLine($"回放数据文件数:{count}");
            this._eventHandler.WaitOne();

        }

        private void Pool_ObjectResolve(object sender, ObjectPoolResolveEventArgs<ISequenceData> e)
        {
            e.Value = new TestSequenceData();
        }

        private void ReplayDataOuputCallback(ISequenceData data)
        {
            var tsd = (TestSequenceData)data;
            Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")}  Replay Time:{tsd.Time.ToString("yyyy-MM-dd HH:mm:ss.fff")} Value:{tsd.Value}");
        }


        private void ReplayEndCallback(string drid, long total, object tag)
        {
            Console.WriteLine($"{drid} 回放完成,共回放:{total}项");
            var destPoint = (EndPoint)tag;
            this._eventHandler.Set();
        }

        public void Dispose()
        {
            this._sdb.Dispose();
            this._eventHandler.Set();
            this._eventHandler.Dispose();
        }
    }

    internal class TestSequenceData : ISequenceData
    {
        public readonly ArraySpan<byte> Data = new ArraySpan<byte>(12);

        public DateTime Time { get; private set; }
        public int Value { get; private set; }



        public TestSequenceData()
        {

        }


        public void Update(DateTime time, int value)
        {
            this.Time = time;
            this.Value = value;

            this._dataIndex = TimeEx.GetTimestamp(time);
            using var writer = new BinaryWriter(new MemoryStream(Data.Array, Data.Offset, Data.Length));
            writer.Write(this._dataIndex);
            writer.Write(value);
        }




        private long _dataIndex = 0L;
        /// <summary>
        /// 数据时间戳
        /// </summary>
        long ISequenceData.DataIndex
        {
            get { return this._dataIndex; }
        }

        /// <summary>
        /// 将当前对象中的数据设置到目标容器数据中
        /// </summary>
        /// <param name="dest">目标容器数据</param>
        void ISequenceData.SetData(DataSpan<byte> dest)
        {
            dest.Update(this.Data.Array, this.Data.Offset, this.Data.Length);
        }

        /// <summary>
        /// 从流中读取指定长度的数据到当前对象
        /// </summary>
        /// <param name="stream">数据流</param>
        /// <param name="length">数组长度</param>
        /// <returns>读取成功返回true,读取失败返回false</returns>
        bool ISequenceData.TryRead(Stream stream, int length)
        {
            this.Data.Check(length);
            if (stream.Read(this.Data.Array, this.Data.Offset, length) == length)
            {
                this._dataIndex = BitConverter.ToInt64(this.Data.Array, 0);
                this.Time = TimeEx.TimestampToDateTime(this._dataIndex);
                this.Value = BitConverter.ToInt32(this.Data.Array, 8);
                return true;
            }
            else
            {
                return false;
            }
        }

    }

}
